package moe.loliserver.command;

import moe.loliserver.legacy.api.PlayerAPI;
import moe.loliserver.legacy.api.ServerAPI;
import moe.loliserver.utils.LoliServerConfigUtil;
import moe.loliserver.LoliServerStart;
import moe.loliserver.legacy.configuration.TickConfig;

import java.util.*;

import net.minecraft.server.MinecraftServer;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;

public class LoliServerCommand extends Command {

    public LoliServerCommand(String name) {
        super(name);
        this.description = "LoliServer related commands";
        this.usageMessage = "/loli [mods|playermods|printthreadcost|item|reload|status]";
        this.setPermission("loliserver.command.loli");
    }

    private List<String> params = Arrays.asList("mods", "playermods", "printthreadcost", "item", "reload", "status");

    @Override
    public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
        List<String> list = new ArrayList<>();
        if (args.length == 1 && (sender.isOp() || testPermission(sender))) {
            for (String param : params) {
                if (param.toLowerCase().startsWith(args[0].toLowerCase())) {
                    list.add(param);
                }
            }
        }

        if (args.length == 2 && args[0].equals("item")) {
            list.add("info");
        }

        return list;
    }

    @Override
    public boolean execute(CommandSender sender, String commandLabel, String[] args) {
        if (!testPermission(sender)) return true;

        if (args.length == 0) {
            sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
            return false;
        }

        switch (args[0].toLowerCase(Locale.ENGLISH)) {
            case "mods":
                // Not recommended for use in games, only test output
                sender.sendMessage(ChatColor.GREEN + "" + ServerAPI.getModSize() + " " + ServerAPI.getModList());
                break;
            case "playermods":
                // Not recommended for use in games, only test output
                if (args.length == 1) {
                    sender.sendMessage(ChatColor.RED + "Usage: " + "/loli playermods <playername>");
                    return false;
                }
                Player player = Bukkit.getPlayer(args[1]);
                if (player != null) {
                    sender.sendMessage(ChatColor.GREEN + "" + PlayerAPI.getModSize(player) + " " + PlayerAPI.getModlist(player));
                } else {
                    sender.sendMessage(ChatColor.RED + "The player [" + args[1] + "] is not online.");
                }
                break;
            case "item":
                if (args.length == 1) {
                    sender.sendMessage(ChatColor.RED + "Usage: /loli item info");
                    return false;
                }
                if ("info".equals(args[1].toLowerCase(Locale.ENGLISH))){
                    ItemCommand.info(sender);
                } else {
                    sender.sendMessage(ChatColor.RED + "Usage: /loli item info");
                }
                break;
            case "reload":
                LoliServerConfigUtil.load();
                TickConfig.ENTITIES.reloadConfig();
                TickConfig.TILES.reloadConfig();
                sender.sendMessage(ChatColor.GREEN + "loliserver-config directory reload complete.");
                break;
            case "status":
                World currentWorld = null;
                if (sender instanceof CraftPlayer) currentWorld = ((CraftPlayer) sender).getWorld();
                final MinecraftServer server = MinecraftServer.getServer();
                sender.sendMessage(ChatColor.YELLOW + "LoliServer - Server Status");
                sender.sendMessage(ChatColor.YELLOW + "---------------------------------------");
                sender.sendMessage(ChatColor.WHITE + "System Info: " + ChatColor.GREEN + System.getProperty("os.name"));
                sender.sendMessage(ChatColor.WHITE + "Running Java: " + ChatColor.GREEN + System.getProperty("java.version"));
                StringBuilder stringBuilder = new StringBuilder(ChatColor.WHITE + "Server Tps(1m, 5m, 15m): " );
                for (double tps : MinecraftServer.getServer().recentTps){
                    stringBuilder.append(format(tps));
                    stringBuilder.append(ChatColor.WHITE + " / ");
                }
                sender.sendMessage(stringBuilder.substring(0, stringBuilder.length() - 2));
                sender.sendMessage(ChatColor.WHITE + "Max Memory: " + ChatColor.GREEN + Runtime.getRuntime().maxMemory()/1024/1024 + " M");
                sender.sendMessage(ChatColor.WHITE + "Used Memory: " + ChatColor.GREEN + Runtime.getRuntime().totalMemory()/1024/1024 + " M");
                sender.sendMessage(ChatColor.WHITE + "Free Memory: " + ChatColor.GREEN + Runtime.getRuntime().freeMemory()/1024/1024 + " M");
                sender.sendMessage(ChatColor.WHITE + "Loaded Plugins: " + ChatColor.GREEN + Bukkit.getPluginManager().getPlugins().length + " Plugins");
                sender.sendMessage(ChatColor.WHITE + "Loaded Mods: " + ChatColor.GREEN + ServerAPI.getModSize() + " Mods");
                sender.sendMessage(ChatColor.WHITE + "Server Players: " + ChatColor.GREEN + Bukkit.getOnlinePlayers().size() + "/" + Bukkit.getMaxPlayers());
                sender.sendMessage(ChatColor.WHITE + "LoliServer Version: " + ChatColor.GREEN + LoliServerStart.getVersion());
                sender.sendMessage(ChatColor.YELLOW + "---------------------------------------");
                sender.sendMessage(ChatColor.YELLOW + "World Info : ");
                for (World world : server.server.getWorlds())
                {
                    if (world instanceof CraftWorld){
                        boolean current = currentWorld != null && currentWorld == world;
                        String bukkitWorldName = world.getName();
                        String name = world.getName();
                        String dimmensionType = Objects.requireNonNull(world.getWorldType()).toString();
                        int levelEntity = world.getEntities().size();
                        int levelChunk = world.getLoadedChunks().length;
                        int levelPlayer = world.getPlayers().size();
                        String displayName = name.equals(bukkitWorldName) ? name : String.format("%s | %s", name, bukkitWorldName);

                        double worldTickTime = mean(server.tickTimes) * 1.0E-6D;
                        double worldTps = Math.min(1000D / worldTickTime, 20);
                        ChatColor chatColor = worldTps >= 19.0 ? ChatColor.GREEN : worldTps >= 15 ? ChatColor.YELLOW : ChatColor.RED;

                        sender.sendMessage(String.format("%s[%s] %s%s %s- %s%.2fMs %s/ %s%.2fTPS / %sEntities / %sChunks / %sPlayers", ChatColor.YELLOW, dimmensionType,
                                current ? ChatColor.GREEN : ChatColor.YELLOW, displayName, ChatColor.RESET,
                                chatColor, worldTickTime, ChatColor.WHITE, chatColor, worldTps, levelEntity, levelChunk, levelPlayer));
                    }
                }
                break;
            default:
                sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
                return false;
        }



        return true;
    }

    private static final long mean(long[] array) {
        if (array == null || array.length == 0) return 0l;
        long r = 0;
        for (long i : array)
            r += i;
        return r / array.length;
    }

    private String format(double tps) {
        return ( ( tps > 18.0 ) ? ChatColor.GREEN : ( tps > 16.0 ) ? ChatColor.YELLOW : ChatColor.RED ).toString()
                + ( ( tps > 20.0 ) ? "[*]" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 );
    }
}
